import datetime
import jwt

from .template import *

# Constants:
JWT_ISSUER = "NulStudio"
JWT_SECRET = "43mG0spaQCqoClFJXprGYegQk"


class TokenInfo:
    def __init__(self, openid: str, unionid: str):
        self.openid: str = openid
        self.unionid: str = unionid


def generate_token(openid: str, unionid: str = '', expire_minutes: int = 24 * 60) -> str:
    data: dict = {
        'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=expire_minutes),
        'iat': datetime.datetime.utcnow(),
        'iss': JWT_ISSUER,
        'data': {
            'openid': openid,
            'unionid': unionid
        }
    }
    encoded: str = str(jwt.encode(data, JWT_SECRET, 'HS256'), 'UTF-8')
    return encoded


def verify_request_token(request: HttpRequest) -> TokenInfo:
    token = request.META.get("HTTP_AUTHORIZATION")
    if not token or not isinstance(token, str):
        raise NulException(ERR_LOGIN_TOKEN_MISSING, ERS_LOGIN_TOKEN_MISSING)

    if token.startswith('Bearer '):
        token = token[7:]

    try:
        decoded: dict = jwt.decode(token, JWT_SECRET, issuer=JWT_ISSUER, algorithms=['HS256'])
        if 'data' not in decoded:
            raise jwt.InvalidTokenError
        data: dict = decoded['data']

        openid = data['openid']
        unionid = data['unionid']
        if not isinstance(openid, str) or not isinstance(unionid, str):
            raise jwt.InvalidTokenError

    except jwt.ExpiredSignatureError:
        raise NulException(ERR_LOGIN_TOKEN_EXPIRED, ERS_LOGIN_TOKEN_EXPIRED)
    except jwt.InvalidTokenError:
        raise NulException(ERR_LOGIN_TOKEN_INVALID, ERS_LOGIN_TOKEN_INVALID)

    return TokenInfo(openid, unionid)
